<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>DTChat</title>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">

    <script src="config.js"></script>
    <script src="shared.js"></script>
    <script src="browsercheck.js"></script>
    <script src="sounds.js"></script>
    <script src="statusLed.js"></script>
    <script src="cjwchat.js"></script>

<!-- Debugger -->
    <script src="Debugger.js"></script>

<!-- JabberConnection -->
    <script src="sha1.js"></script>
    <script src="xmlextras.js"></script>
    <script src="JSJaCConnection.js"></script>
    <script src="JSJaCHttpPollingConnection.js"></script>
    <script src="JSJaCHttpBindingConnection.js"></script>
    <script src="JSJaCPacket.js"></script>
<!--
	Here, first get user name from cookie, 
	If no user name, send an request to server to ask a name,
	if have user name, use the name to login.
-->    
    <script>
    
    </script>

    <script>
<!--

 /* ***
  * JWChat, a web based jabber client
  * Copyright (C) 2003-2004 Stefan Strigler <steve@zeank.in-berlin.de>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  *
  * Please visit http://jwchat.sourceforge.net for more information!
  */

/************************************************************************
 *                       ******  GLOBAL WARS(tm) *******
 ************************************************************************
 */
var jid;
var pass;
var register = false; // whether to register new account
var nick;
var vcard;
var status = '';
var onlstat = '';
var onlmsg = '';
var autoPopup = true;
var autoPopupAway = false;
var playSounds = true;
var focusWindows = true;
var timestamps = false;
var usersHidden = false;
var enableLog = false;
var loghost;

/* some globals */
var roster;
var fmd; // frames.main.document

var statusLed;
var statusMsg;

var onlstatus = new Object();
onlstatus["available"] = "online";
onlstatus["chat"] = "free for chat";
onlstatus["away"] = "away";
onlstatus["xa"] = "not available";
onlstatus["dnd"] = "do not disturb";
onlstatus["invisible"] = "invisible";
onlstatus["unavailable"] = "offline";


/************************************************************************
 *                         ****** Pop-Up's *******
 ************************************************************************
 */

function openGroupchat(aJid,nick,pass) {
	pass = pass || '';
	nick = nick || '';

  var user = roster.getUserByJID(aJid);
  if(!user) {
    user = roster.addUser(new RosterUser(aJid,'',["Chat Rooms"],aJid.substring(0,aJid.indexOf('@'))));
		user.type = 'groupchat';
    roster.print();
  }
	if (!user.chatW || user.chatW.closed)
		user.chatW = open("groupchat.html?jid="+escape(aJid)+"&nick="+escape(nick)+"&pass="+escape(pass),"gchatW"+makeWindowName(aJid+"/"+nick),"width=520,height=390,resizable=yes");
	user.chatW.focus();
}

var subw;
function openSubscription(aJid) {
  var param = (aJid) ? "?jid="+escape(aJid) : "";
  subw = open("subscription.html"+param,"sub","width=320,height=240,resizable=yes");
	subw.focus();
  return false;
}

function openCustomPresence(aJid) {
	var user = roster.getUserByJID(aJid);
	if (!user)
		return;
  if (!user.onlStatW || user.onlStatW.closed)
    user.onlStatW = open("changestatus.html?jid="+escape(aJid),"onlStatW","width=330,height=240,resizable=yes");
  user.onlStatW.focus();
  return false;
}

function sendCustomPresence(aJid,presence,msg) {
	var oPresence = new JSJaCPresence();
	oPresence.setTo(aJid);
	if (roster.getUserByJID(aJid).roster)
		oPresence.setXMLNS();

	switch (presence) {
	case 'offline':
		oPresence.setType('unavailable');
	case 'unavailable':
		oPresence.setType('unavailable');
		presence = "invisible";
	default:
		if (presence != 'available')
			oPresence.setShow(presence);
	}

	if (typeof(msg) != 'undefined' && msg != '')
		oPresence.setStatus(msg);

	Debug.log(oPresence.getDoc().xml,2);
	con.send(oPresence);
}

function openUserProps(aJid) {
  open("userprops.html?jid="+escape(aJid),"uProps"+makeWindowName(aJid),"width=480,height=360,resizable=yes");
  return false;
}

function removeUser(aJid) {
	// get fulljid
	var fulljid = roster.getUserByJID(aJid).fulljid;

	var iq = new JSJaCIQ();
	iq.setType('set');
	var query = iq.setQuery('jabber:iq:roster');
	var item = query.appendChild(iq.getDoc().createElement('item'));
	item.setAttribute('jid',fulljid);
	item.setAttribute('subscription','remove');

	con.send(iq);
}

var vcardW; // my vcardW;
function openUserInfo(aJid) {
	var newin = open("vcard.html?jid="+escape(aJid),"vcardW"+makeWindowName(aJid),"width=400,height=580,scrollbars=yes");

	if (cutResource(aJid) == cutResource(jid))
		vcardW = newin;
	else {
		var user = roster.getUserByJID(cutResource(aJid));
		if (!user) {
			user = new RosterUser(aJid);
			roster.addUser(user);
		}
		if (user.roster) // groupchat(!)
			user = user.roster.getUserByJID(aJid);
		user.vcardW = newin;
	}

	return false;
}

function openUserHistory(aJid) {

	if (typeof(loghost) == 'undefined' || loghost == '')
		return;

	var user = roster.getUserByJID(aJid);

	if (user == null)
		return;

	if (!user.histW || user.histW.closed)
		user.histW = open("userhist.html?jid="+escape(aJid),"histW"+makeWindowName(aJid),"width=600,height=400,resizable=yes,scrollbars=no");
	user.histW.focus();
}

function openUserNote(aJid) { /* store annotations to a user */
	var user = roster.getUserByJID(aJid);

	if (user == null)
		return; // unbelievable

	if (!user.noteW || user.noteW.closed)
		user.noteW = open("usernote.html?jid="+escape(aJid),"noteW"+makeWindowName(aJid),"width=300,height=200,resizable=yes,scrollbars=no");
	user.noteW.focus();
}

var searchW;
function openSearch() {
	if (!searchW || searchW.closed)
		searchW = open("search.html","searchW"+makeWindowName(jid),"width=480,height=260,resizable=yes,scrollbars=yes");
	searchW.focus();
	return false;
}

var ebW
function openEditBookmarks() {
	if (!ebW || ebW.closed)
		ebW = open("editbookmarks.html","ebw"+makeWindowName(jid),"width=330,height=290,resizable=yes");
	return false;
}


/************************************************************************
 * nifty helpers - always there if you need 'em
 ************************************************************************
 */

/* command line history */
var messageHistory = new Array();
var historyIndex = 0;
function getHistory(key, message) {
  if ((key == "up") && (historyIndex > 0)) historyIndex--;
  if ((key == "down") && (historyIndex < messageHistory.length)) historyIndex++;
  if (historyIndex >= messageHistory.length) {
    if (historyIndex == messageHistory.length) return '';
    return message;
  } else {
    return messageHistory[historyIndex];
  }
}

function addtoHistory(message) {
  if (is.ie5)
    messageHistory = messageHistory.concat(message);
  else
    messageHistory.push(message);
  historyIndex = messageHistory.length;
}

/* system sounds */
var soundPlaying = false;
function soundLoaded() {
	soundPlaying = false;
}

function playSound(action) {
  if (!playSounds)
    return;

  if(!SOUNDS[action]) {
    Debug.log("no sound for '" + action + "'",1);
    return;
  }

	if (onlstat != '' && onlstat != 'available' && onlstat != 'chat')
		return;

	if (soundPlaying)
		return;

	soundPlaying = true;
	
  var frameD = frames["jwc_sound"].document;

  var html = "<embed src=\""+SOUNDS[action]+"\" width=\"1\" height=\"1\" quality=\"high\" pluginspage=\"http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash\" type=\"application/x-shockwave-flash\">";
  frameD.open();
  //frameD.write(html);
  frameD.close();
}


function isGateway(aJid) {
	aJid = cutResource(aJid);
	for (var i in disco)
		if (i == aJid)
			if (disco[i].getNode().getElementsByTagName('identity').item(0)) {
				if (disco[i].getNode().getElementsByTagName('identity').item(0).getAttribute('category') == 'gateway')
					return true;
			}

	return false;
}

function storeCID(iq,jid) {
	if (!iq || iq.getType() != 'result')
		return;

	Debug.log(iq.getDoc().xml,2);
	var user = roster.getUserByJID(jid);
	if (user == null) {
		Debug.log("user with jid " + jid + " not found",1);
		return;
	}

	if (user.chatW && !user.chatW.closed) // store cid
		user.chatW.cid = iq.getNode().firstChild.getAttribute('cid');
}

/************************************************************************
 *                       ******  CHANGESTATUS   *******
 ************************************************************************
 */

function sendPresence2Groupchats(gc,val,away) {
	var aPresence;
	for (var i=0; i<gc.length; i++) {
		aPresence = new JSJaCPresence();
		//aPresence.setXMLNS();
		aPresence.setTo(gc[i]);
		if (away && away != '')
			aPresence.setStatus(away);
		if (val != 'available')
			aPresence.setShow(val);
		con.syncSend(aPresence);
	}
}

function changeStatus(val,away) {
  
  Debug.log("changeStatus: "+val+","+away, 2);
  
  onlstat = val;
	if (away)
		onlmsg = away;

	if (!con.connected() && val != 'offline') {
		init();
		return;
	}
		

	var aPresence = new JSJaCPresence();
  
  switch(val) {
  case "unavailable":
    val = "invisible";
		aPresence.setType('invisible');
    break;
  case "offline":
    val = "unavailable";
		aPresence.setType('unavailable');
		con.syncSend(aPresence);
		con.disconnect();
    var img = eval(val+"Led");
    statusLed.src = img.src;
    if (away)
      statusMsg.value = away;
    else
      statusMsg.value = onlstatus[val];
    cleanUp();
    return;
    break;
  case "available":
    val = 'available'; // needed for led in status bar
    if (away) {
			aPresence.setStatus(away);
    }
		aPresence.setPriority(8);
		break;
	case "chat":
		aPresence.setPriority(8);
  default:
    if (away) {
			aPresence.setStatus(away);
    }
		aPresence.setShow(val);
  }

	con.syncSend(aPresence);

  /* send presence to chatrooms
   */
  if (typeof(roster) != 'undefined' && onlstat != 'invisible') {
		sendPresence2Groupchats(roster.getGroupchats(),onlstat,onlmsg);
  }

  var img = eval(val+"Led");
	statusLed.src = img.src;
	if (away)
		statusMsg.value = away;
	else
		statusMsg.value = onlstatus[val];
}

/************************************************************************
 *                   ***** EVENT - HANDLER *****
 ************************************************************************
 */


/************************************************************************
 * handleMessage
 ************************************************************************
 */
function handleMessage(aMessage) {

	Debug.log(aMessage.getDoc().xml,2);

	if (aMessage.getType() == 'error')
		return;

	/* check if this is a groupchat invite */
	var x;
	for (var i=0; i<aMessage.getNode().getElementsByTagName('x').length; i++)
		if (aMessage.getNode().getElementsByTagName('x').item(i).getAttribute('xmlns') == 'http://jabber.org/protocol/muc#user') {
			x = aMessage.getNode().getElementsByTagName('x').item(i);
			break;
		}

	if (x) {
		var from, to, reason, pass;
		to = aMessage.getFrom();
		var aInvite = x.getElementsByTagName('invite').item(0);
		from = aInvite.getAttribute('from');
		if (aInvite.firstChild && aInvite.firstChild.nodeName == 'reason' && aInvite.firstChild.firstChild)
			reason = aInvite.firstChild.firstChild.nodeValue;
		if (x.getElementsByTagName('password').item(0))
			pass = x.getElementsByTagName('password').item(0).firstChild.nodeValue;
		Debug.log("You have been invited to " + jid + " pass " + pass + " by " + from + "\nreason:" + reason,2);
		var user = roster.getUserByJID(cutResource(from));
		if (!user) {// users not in roster (yet)
			Debug.log("creating new user "+from,3);
			user = roster.addUser(new RosterUser(cutResource(from)));
			user.lastsrc = eval(user.status + "Led").src;
			roster.print();
		}

		if (typeof(user.iwArr) == 'undefined')
			user.iwArr = new Array();

		user.iwArr[to] = open("groupchat_invite.html?to="+escape(to)+"&from="+escape(from)+"&pass="+escape(pass)+"&reason="+escape(reason),"iw"+makeWindowName(to),"width=320,height=320,resizable=yes");
		
		return;
	}

  var from = cutResource(aMessage.getFrom());
  var type = aMessage.getType();
  Debug.log("from: "+from+"\naMessage.getFrom(): "+aMessage.getFrom(),3);

  var user = roster.getUserByJID(from);
  if (user == null) {// users not in roster (yet)
    Debug.log("creating new user "+from,3);
    user = roster.addUser(new RosterUser(from));
    user.lastsrc = eval(user.status + "Led").src;
    roster.print();
  }

  Debug.log("got user jid: "+user.jid,3);

  var aRoster = roster;
  if (type != 'groupchat' && user.roster && from != aMessage.getFrom()) { // private groupchat message
    aRoster = user.roster;
    
    from = aMessage.getFrom(); // use from with resource (had been cut off first)
    user = user.roster.getUserByJID(from);
  }

  /* change icon in roster - but not if it's a groupchat item */
  if (type != 'groupchat') {
    if (!user.lastsrc)
      user.lastsrc = eval(user.status + "Led").src;
      
    var images = aRoster.getUserIcons(from);
    for (var i=0; i<images.length; i++)
      images[i].src = messageImg.src;

    /* user is not visible right now - make him pop up (lastsrc changed!) */
    if (aRoster.usersHidden && user.status == 'unavailable')
      aRoster.print();
  }

	// set current timestamp
	var x;
	for (var i=0; i<aMessage.getNode().getElementsByTagName('x').length; i++)
		if (aMessage.getNode().getElementsByTagName('x').item(i).getAttribute('xmlns') == 'jabber:x:delay') {
			x = aMessage.getNode().getElementsByTagName('x').item(i);
			break;
		}

	if (x) {
			Debug.log("found offline message: "+x.getAttribute('stamp'),3);
			var stamp = x.getAttribute('stamp');
			aMessage.jwcTimestamp = new Date(Date.UTC(stamp.substring(0,4),stamp.substring(4,6)-1,stamp.substring(6,8),stamp.substring(9,11),stamp.substring(12,14),stamp.substring(15,17)));
	} else
		aMessage.jwcTimestamp = new Date();

  if (type == 'chat') {
    
    user.chatmsgs = user.chatmsgs.concat(aMessage);
    
    if (user.chatW && !user.chatW.closed && user.chatW.popMsgs) {
      user.chatW.popMsgs();
      playSound('chat_recv');
    } else if (autoPopup && (autoPopupAway || onlstat == "available" || onlstat == "chat")) {
      aRoster.openChat(from);
      playSound('chat_recv');
    } else {
      if (focusWindows) window.focus();
      playSound('chat_queue');

			// let arrow blink for toggled groups
			for (var i in user.groups) {
				if (user.groups[i] != '') {
					if (roster.hiddenGroups[user.groups[i]])
						fmd.images[user.groups[i]+"Img"].src = arrow_right_blinking.src;
				}					
			}
    }

		// send back to server - [TODO]
		if (enableLog && typeof(loghost) != 'undefined') {
			var aIQ = new JSJaCIQ();
			aIQ.setType('set');
			aIQ.setTo(loghost);
			var aNode = aIQ.getNode().appendChild(aIQ.getDoc().createElement('archive'));
			aNode.setAttribute('xmlns','http://jabber.org/protocol/archive');
			aNode.appendChild(aMessage.getNode().cloneNode(true));
			if (user.chatW && !user.chatW.closed && typeof(user.chatW.cid)!='undefined') {
				aNode.setAttribute('cid',user.chatW.cid);
				con.send(aIQ);
			} else
				con.send(aIQ,storeCID,user.jid);
		}
  } else if (type == 'groupchat') {

      /* handle groupchat message 
       */

    user.chatmsgs = user.chatmsgs.concat(aMessage);
    if (user.chatW && !user.chatW.closed && user.chatW.srcW && typeof(user.chatW.srcW.roster) != 'undefined' && user.chatW.popMsgs) {
      user.chatW.popMsgs();
    } 

    playSound('chat_recv');
    
  } else {

    user.messages = user.messages.concat(aMessage);
    if (autoPopup && (autoPopupAway || onlstat == "available" || onlstat == "chat") && (!user.mW || user.mW.closed)) {
      aRoster.openMessage(from);
      playSound('message_recv');
    } else if (user.mW && !user.mW.closed && user.messages.length > 0 && user.mW.document.forms[0]) {
      user.mW.document.forms[0].nextButton.disabled = false;
      if (focusWindows) user.mW.focus();
      playSound('message_recv');
    }	else {
      if (focusWindows) window.focus();
      playSound('message_queue');
			// let arrow blink for toggled groups
			for (var i in user.groups) {
				if (user.groups[i] != '') {
					if (roster.hiddenGroups[user.groups[i]])
						fmd.images[user.groups[i]+"Img"].src = arrow_right_blinking.src;
				}					
			}

    }

		// store message
		if (enableLog && typeof(loghost) != 'undefined') {
			var aIQ = new JSJaCIQ();
			aIQ.setType('set');
			aIQ.setTo(loghost);
			var aNode = aIQ.getNode().appendChild(aIQ.getDoc().createElement('archive'));
			aNode.setAttribute('xmlns','http://jabber.org/protocol/archive');
			aNode.appendChild(aMessage.getNode().cloneNode(true));
			con.send(aIQ);
		}
  }
}

/************************************************************************
 * handleMessageError
 ************************************************************************
 */
var error_messages = new Array();
var errorW;
function handleMessageError(aJSJaCPacket) {

	if (aJSJaCPacket.getType() != 'error')
		return;

	Debug.log(aJSJaCPacket.getDoc().xml,3);

	var user = roster.getUserByJID(cutResource(aJSJaCPacket.getFrom()));

	if (user.chatW && !user.chatW.closed && user.chatW.putMsgHTML) {
		var error = aJSJaCPacket.getNode().getElementsByTagName('error').item(0);
		if (error) {
			if (error.getElementsByTagName('text').item(0)) {
				user.chatW.putMsgHTML(error.getElementsByTagName('text').item(0).firstChild.nodeValue,new Date(),aJSJaCPacket.getFrom(),null,true);
				playSound('error');
				return;
			}
		}
	}

	error_messages = error_messages.concat(aJSJaCPacket);

	if (!errorW || errorW.closed)
		errorW = open("error_message.html","errorW"+makeWindowName(jid),"width=360,height=270,dependent=yes,resizable=yes");
	else if (error_messages.length > 0 && errorW.document.forms[0])
		errorW.document.forms[0].nextButton.disabled = false;

	playSound('error');

	errorW.focus();
}

/************************************************************************
 * handlePresence
 ************************************************************************
 */

function handlePresence(presence) {
	Debug.log(presence.getDoc().xml,2);

  var from = cutResource(presence.getFrom());
	var type = presence.getType();
	var show = presence.getShow();
	var status = presence.getStatus();

  var aRoster = roster;

  if (from == cutResource(jid)) // skip my own presence msgs
    return;

  if (type) {
    if (type == 'subscribe') {
			if (isGateway(from)) { // automatically subscribe to gateways
				var aPresence = new JSJaCPresence();
				aPresence.setTo(from);
				aPresence.setType('subscribed');
				con.send(aPresence);
			}
			else
				if (status)
					window.open("subscriptionRequest.html?jid="+escape(from)+"&msg="+escape(status),"sr"+makeWindowName(from),"width=320,height=240");
				else
					window.open("subscriptionRequest.html?jid="+escape(from),"sr"+makeWindowName(from),"width=320,height=240");

      return;
    }
    if (type == 'unsubscribe')
      alert("You have been unsubscribed from "+presence.getFrom()); /* [TODO] don't use alert here */

		if (type == 'error') { // [TODO]

			var user = roster.getUserByJID(from);
			if (user && user.chatW && !user.chatW.closed && user.chatW.putMsgHTML) {
				if (presence.getNode().getElementsByTagName('error').item(0)) {
					var error = presence.getNode().getElementsByTagName('error').item(0);
					if (error.getElementsByTagName('text').item(0))
						user.chatW.putMsgHTML(error.getElementsByTagName('text').item(0).firstChild.nodeValue,new Date(),from,null,true);
					else if (error.firstChild && error.firstChild.nodeValue)
						user.chatW.putMsgHTML(error.firstChild.nodeValue,new Date(),from,null,true);								
				}
				
			}
// 			for (var i in jabber.o) {
// 				if (jabber.o[i].tagname == 'error' && jabber.o[i].data != '')
// 					alert("From: "+from+"\nError (Code:"+jabber.o[i].code+")\n\n"+jabber.o[i].data);
// 			}
			return;
		}
  }

  var user = roster.getUserByJID(from);
  if (!user) // presence from unsubscribed user
    return;

	/* handle presence for MUC */
	var x;
	for (var i=0; i<presence.getNode().getElementsByTagName('x').length; i++)
		if (presence.getNode().getElementsByTagName('x').item(i).getAttribute('xmlns') == 'http://jabber.org/protocol/muc#user') {
			x = presence.getNode().getElementsByTagName('x').item(i);
			break;
		}

  if (user.roster && x) { 
    var ofrom = presence.getFrom().substring(presence.getFrom().indexOf('/')+1);

    Debug.log("jabber.from:"+presence.getFrom()+", ofrom:"+ofrom,3);

    var ouser = user.roster.getUserByJID(presence.getFrom());
    if (!ouser) // no user? create one!
      ouser = new GroupchatRosterUser(presence.getFrom(),ofrom);

		var item = x.getElementsByTagName('item').item(0);

		ouser.affiliation = item.getAttribute('affiliation');
		ouser.role = item.getAttribute('role');
		ouser.nick = item.getAttribute('nick');
		ouser.realjid = item.getAttribute('jid');
		if (item.getElementsByTagName('reason').item(0))
			ouser.reason = item.getElementsByTagName('reason').item(0).firstChild.nodeValue;
		if (actor = item.getElementsByTagName('actor').item(0)) {
			if (actor.getAttribute('jid') != null)
				ouser.actor = actor.getAttribute('jid');
			else if (item.getElementsByTagName('actor').item(0).firstChild != null)
				ouser.actor = item.getElementsByTagName('actor').item(0).firstChild.nodeValue;
		}
		if (ouser.role != '') {
			ouser.add2Group(ouser.role+'s');
			
			/* check if it is our own presence
			 * must be done here cause we want to be sure that role != ''
			 */
            
			if (ouser.name == user.roster.nick) { // seems to be me
				user.roster.me = ouser; // store this reference
				if (user.chatW.updateMe)
					user.chatW.updateMe();
			}
		}

		Debug.log("ouser.jid: "+ ouser.jid + ", ouser.fulljid:" + ouser.fulljid + ", ouser.name:"+ouser.name+", user.roster.nick:"+user.roster.nick,3);


		var nickChanged = false;
		if (x.getElementsByTagName('status').item(0)) {
			var code = x.getElementsByTagName('status').item(0).getAttribute('code');
			switch (code) {
			case '201': // room created
				/* popup dialog to ask for whether to accept default
				 * configuration or make a custom room 
				 */
				if (confirm("A new room has been created but it awaits configuration from you. Do you want to do a custom configuration now?\nNote: Click on 'Cancel' to start with a default configuration!"))
					user.chatW.openConfig();
				else {
					var iq = new JSJaCIQ();
					iq.setType('set');
					iq.setTo(user.jid);
					var query = iq.setQuery('http://jabber.org/protocol/muc#owner');
					var x = query.appendChild(iq.getDoc().createElement('x'));
					x.setAttribute('xmlns','jabber:x:data');
					x.setAttribute('type','submit');
					
					con.send(iq);
				}
				break;
			case '303': // nick change
				// display message
				if (!ouser.nick)
					return;

				var aMessage = new JSJaCMessage();
				aMessage.setFrom(user.jid);
				aMessage.setBody(""+ouser.name+" is now known as "+ouser.nick);
				user.chatmsgs = user.chatmsgs.concat(aMessage);
				if (user.chatW && !user.chatW.closed && user.chatW.popMsgs)
					user.chatW.popMsgs();

				// update nick if it's me
				if (ouser.name == user.roster.nick)
					user.roster.nick = ouser.nick;

				// remove old user
				var aChatW = ouser.chatW;
				user.roster.removeUser(ouser);

				// add new user
				ouser = new GroupchatRosterUser(presence.getFrom().substring(0,presence.getFrom().lastIndexOf('/')+1).concat(ouser.nick),ouser.nick);

				if (aChatW && !aChatW.closed) {
					ouser.chatW = aChatW;
					ouser.chatW.user = ouser;
				}
				user.roster.addUser(ouser);
				nickChanged = true;
				break;
			case '301': // user has been kicked
				var aMessage = new JSJaCMessage();
				aMessage.setFrom(user.jid);
				var body;
				if (ouser.actor)
					body = ""+ouser.name+" has been banned by "+ouser.actor;
				else
					body = ""+ouser.name+" has been banned";
				if (ouser.reason)
					body += ": " + ouser.reason;
				aMessage.setBody(body);
				user.chatmsgs = user.chatmsgs.concat(aMessage);
				if (user.chatW && !user.chatW.closed && user.chatW.popMsgs)
					user.chatW.popMsgs();			
				
				playSound('chat_recv');
				break;
			case '307': // user has been kicked
				var aMessage = new JSJaCMessage();
				aMessage.setFrom(user.jid);
				var body;
				if (ouser.actor)
					body = ""+ouser.name+" has been kicked by "+ouser.actor;
				else
					body = ""+ouser.name+" has been kicked";
				if (ouser.reason)
					body += ": " + ouser.reason;
				aMessage.setBody(body);
				user.chatmsgs = user.chatmsgs.concat(aMessage);
				if (user.chatW && !user.chatW.closed && user.chatW.popMsgs)
					user.chatW.popMsgs();	
							
				playSound('chat_recv');
				break;
			}
		}

    Debug.log("<"+ouser.name+"> affiliation:"+ouser.affiliation+", role:"+ouser.role,3);

    if (!user.roster.getUserByJID(presence.getFrom()) && !nickChanged) {
			// add user
      user.roster.addUser(ouser);

			// show join message
			var aMessage = new JSJaCMessage();
			aMessage.setFrom(user.jid);
			aMessage.setBody(""+ouser.name+" has become available");
			user.chatmsgs = user.chatmsgs.concat(aMessage);
			if (user.chatW && !user.chatW.closed && user.chatW.popMsgs)
				user.chatW.popMsgs();			

			playSound('online');

    } else if (presence.getType() == 'unavailable' && !nickChanged) {
			// show part message
			var aMessage = new JSJaCMessage();
			aMessage.setFrom(user.jid);
			var body = ""+ouser.name+" has left";
			if (presence.getStatus())
				body += ": " + presence.getStatus();
			aMessage.setBody(body);
			user.chatmsgs = user.chatmsgs.concat(aMessage);
			if (user.chatW && !user.chatW.closed && user.chatW.popMsgs)
				user.chatW.popMsgs();			

			playSound('offline');

		} else
      user.roster.updateGroups();

    // relink roster and user
    aRoster = user.roster;
    user = ouser;
  } 

  if (show) {
    if (user.status == 'unavailable')
      playSound('online');
		// fix broken pressenc status
		if (show != 'chat' && show != 'away' && show != 'xa' && show != 'dnd')
			show = 'available';
    user.status = show;
  } else if (type) {
    if (type == 'unsubscribe') {
      user.subscription = 'from';
      user.status = 'stalker';
    } else if (user.status != 'stalker')
      user.status = 'unavailable';
    if (aRoster.name == 'GroupchatRoster' && !nickChanged) { // it's a groupchat roster
			// remove user
			if (!user.chatW || user.chatW.closed)
				aRoster.removeUser(user); // we don't need offline users in there
		}
    playSound('offline');
  } else {
    if (user.status == 'unavailable') // user was offline before
      playSound('online');
    user.status = 'available';
  }

	var img = eval(user.status+"Led");
  
  if (user.lastsrc) // message is pending
    user.lastsrc = img.src;
  
  // show away message
  if (status)
    user.statusMsg = status;
  else
    user.statusMsg = null;
  
	// update presence indicator of chat window
	if (user.chatW && !user.chatW.closed && user.chatW.updateUserPresence) 
		user.chatW.updateUserPresence();

  aRoster.print(); // update roster
}

/************************************************************************
 * handleIQSet
 ************************************************************************
 */

function handleIQSet(iq) {
  if (iq.getType() != "set") {
		Debug.log("not handling iq:\n"+iq.getDoc().xml,3);
    return;
	}

  Debug.log("got iq type 'set':\n"+iq.getDoc().xml,2);

	if (iq.getQueryXMLNS() != 'jabber:iq:roster') { // only handle roster items so far
		Debug.log("not handling iq:\n"+iq.getDoc().xml,1);
		return;
	}

  for (var i=0; i<iq.getQuery().childNodes.length; i++) {
    var item = iq.getQuery().childNodes.item(i);
    var user = roster.getUserByJID(cutResource(item.getAttribute('jid')));
    if (user) {
      user.subscription = item.getAttribute('subscription');
      if (item.getAttribute('subscription') == 'remove') {
				Debug.log("removing user " + user.jid,2);
        roster.removeUser(user);
      } else { // update user
        user.name = item.getAttribute('name')? item.getAttribute('name') : item.getAttribute('jid');
        user.groups = new Array('');
				for (var j=0; j<item.childNodes.length; j++)
					if (item.childNodes.item(j).nodeName == 'group')
						user.groups = user.groups.concat(item.childNodes.item(j).firstChild.nodeValue);
        roster.updateGroups();
      }
			if (item.getAttribute('subscription') == "from")
				openSubscription(item.getAttribute('jid')); // subscribe to user
    } else {// got a new user
			if (isGateway(cutResource(item.getAttribute('jid')))) { // auto add
				// get name
				var name = cutResource(item.getAttribute('jid'));
				for (var i in disco)
					if (i == cutResource(item.getAttribute('jid')))
						name = disco[i].getQuery().getElementsByTagName('identity').item(0).getAttribute('name');

				// add to roster
				var aUser = new RosterUser(cutResource(item.getAttribute('jid')),item.getAttribute('subscription'),["Gateways"],name);
				aUser.fulljid = item.getAttribute('jid');
				roster.addUser(aUser);

				// tell server about it
				var aIQ = new JSJaCIQ();
				aIQ.setType('set');
				var query = aIQ.setQuery('jabber:iq:roster');
				var aItem = query.appendChild(aIQ.getDoc().createElement('item'));
				aItem.setAttribute('jid',cutResource(item.getAttribute('jid')));
				aItem.setAttribute('name',name);
				aItem.appendChild(iq.getDoc().createElement('group')).appendChild(iq.getDoc().createTextNode('Gateways'));

				con.send(aIQ);
			} else {
        var name = item.getAttribute('name')? item.getAttribute('name') : item.getAttribute('jid');
				if (name.indexOf('@') != -1)
					name = name.substring(0,name.indexOf('@'));

				item.setAttribute('name',name);
        var groups = new Array('');
				for (var j=0; j<item.childNodes.length; j++)
					if (item.childNodes.item(j).nodeName == 'group')
						groups = groups.concat(item.childNodes.item(j).firstChild.nodeValue);
				
				roster.addUser(new RosterUser(item.getAttribute('jid'),item.getAttribute('subscription'),groups,name));

				var aIQ = new JSJaCIQ();
				aIQ.setType('set');
				var query = aIQ.setQuery('jabber:iq:roster');

				var aItem = item.cloneNode(true);
				aItem.removeAttribute('subscription');
				query.appendChild(aItem);

				con.send(aIQ); // set stripped name

				if (item.getAttribute('subscription') == "from")
					openSubscription(item.getAttribute('jid')); // subscribe to user
			}
    }
  }
  roster.print();
}

function handleConError(e) {
	switch (e.getAttribute('code')) {
	case '401':
		alert("Authorization failed");
		if (!con.connected())
			window.close();
		break;
	case '409':
		alert("Registration failed!\n\nPlease choose a different username!");
		break;
	case '503':
		alert("Service unavailable");
		break;
	case '500':
		if (!con.connected())
			if (confirm("Internal Server Error.\n\nDisconnected.\n\nReconnect?"))
				changeStatus(onlstat,onlmsg);
		break;
	default:
		alert("An Error Occured:\nCode: "+e.getAttribute('code')+"\nType: "+e.getAttribute('type')+"\nCondition: "+e.firstChild.nodeName); // this shouldn't happen :)
		break;
	}
}

function handleDisconnect() {
	if (logoutCalled || onlstat == 'offline')
		return;

	// disconnecting not with onunload handler triggered
	statusLed.src = unavailableLed.src; // offline icon
	statusMsg.value = '';

  fmd.getElementById('roster').innerHTML = '';

// 	if (confirm("Disconnected\n\nReconnect?"))
// 		changeStatus(onlstat,onlmsg);
}

function handleConnected() {

	Debug.log("Connected",0);

	if (register && opener && opener.document.forms[0] && opener.document.forms[0].register)
		opener.document.forms[0].register.checked = false; 

	/* get/setup roster */
	iq = new JSJaCIQ();
	iq.setIQ(null,null,'get','roster_1');
	iq.setQuery('jabber:iq:roster');
	con.send(iq,getRoster); // cascading information retrieval
}

/* *** cascading onconnect handlers *** */
function getRoster(iq) {
	//alert("cjwchat.html:getRoster");
	if (!iq || iq.getType() != 'result') {
		if (iq)
			Debug.log("Error fetching roster:\n"+iq.getDoc().xml,1);
		else
			Debug.log("Error fetching roster",1);
		return;
	}

	Debug.log("got roster:\n"+iq.getDoc().xml,2);
	
	roster = new Roster(iq.getQuery().childNodes,fmd);
	roster.usersHidden = usersHidden;
	roster.nick = jid.substring(0,jid.indexOf('@')); // remember nick for 1:1 Chats

	alert("cjwchat.html:will begin chat");
	beginChat();
	
	// get saved state
	iq = new JSJaCIQ();
	iq.setIQ(null,null,'get','jwchat_state');
	var query = iq.setQuery('jabber:iq:private');
	query.appendChild(iq.getDoc().createElement('jwchat')).setAttribute('xmlns','jwchat:state');

	con.send(iq,getSavedState);
}

function getSavedState(iq) {
	if (!iq || iq.getType() != 'result')
		if (iq)
			Debug.log("Error retrieving saved state:\n"+iq.getDoc().xml,1);
		else
			Debug.log("Error retrieving saved state",1);
			
	if (iq && iq.getType() == 'result') {
		Debug.log(iq.getDoc().xml,3);
		var jNode = iq.getNode().getElementsByTagName('jwchat').item(0);
		for (var i=0; i<jNode.childNodes.length; i++) {
			var item = jNode.childNodes.item(i);
			if (item.nodeName == 'presence' && item.firstChild && onlstat == '')
				onlstat = item.firstChild.nodeValue;
			if (item.nodeName == 'hiddenGroups' && item.firstChild) {
				var hiddenGroups = item.firstChild.nodeValue.split(',');
				for (var j in hiddenGroups)
					if (hiddenGroups[j] != '')
						roster.hiddenGroups[hiddenGroups[j]] = true;
			}
		}
	}

	// get prefs
	iq = new JSJaCIQ();
	iq.setIQ(null,null,'get','jwchat_prefs');
	var query = iq.setQuery('jabber:iq:private');
	query.appendChild(iq.getDoc().createElement('jwchat')).setAttribute('xmlns','jwchat:prefs');

	con.send(iq,getPrefs);
}

function getPrefs(iq) {
	if (!iq || iq.getType() != 'result')
		if (iq)
			Debug.log("Error retrieving preferences:\n"+iq.getDoc().xml,1);
		else
			Debug.log("Error retrieving preferences",1);

	if (iq && iq.getType() == 'result') {
		Debug.log(iq.getDoc().xml,3);
		if (iq.getNode().getElementsByTagName('jwchat').item(0)) {
			var jNode = iq.getNode().getElementsByTagName('jwchat').item(0);
			for (var i=0; i<jNode.childNodes.length; i++) {
				switch (jNode.childNodes.item(i).nodeName) {
				case 'usersHidden':
					if (eval(jNode.childNodes.item(i).firstChild.nodeValue))
						roster.toggleHide();
					break;
				case 'timerval':
					timerval = eval(jNode.childNodes.item(i).firstChild.nodeValue);
					con.setPollInterval(timerval);
					break;
				case 'autoPopup':
					autoPopup = eval(jNode.childNodes.item(i).firstChild.nodeValue);
					break;
				case 'autoPopupAway':
					autoPopupAway = eval(jNode.childNodes.item(i).firstChild.nodeValue);
					break;
				case 'playSounds':
					playSounds = eval(jNode.childNodes.item(i).firstChild.nodeValue);
					break;
				case 'focusWindows':
					focusWindows = eval(jNode.childNodes.item(i).firstChild.nodeValue);
					break;
				case 'timestamps':
					timestamps = eval(jNode.childNodes.item(i).firstChild.nodeValue);
					break;
				case 'enableLog':
					enableLog = eval(jNode.childNodes.item(i).firstChild.nodeValue);
					break;
				}
			}
		}
	}

	// print roster
	roster.print();

	// send presence
	if (onlstat == '')
		onlstat = 'available';
	changeStatus(onlstat);

	playSound('connected');

	// Start Service Discovery
	iq = new JSJaCIQ();
	iq.setIQ(con.server,null,'get','disco_item_1');
	iq.setQuery('http://jabber.org/protocol/disco#items');

	con.send(iq,getDiscoItems);

	// get bookmarks
	iq = new JSJaCIQ();
	iq.setIQ(null,null,'get','storage_bookmarks');
	var query = iq.setQuery('jabber:iq:private');
	query.appendChild(iq.getDoc().createElement('storage')).setAttribute('xmlns','storage:bookmarks');

	con.send(iq,getBookmarks);

	// get annotations
	iq = new JSJaCIQ();
	iq.setIQ(null,null,'get','jwchat_notes');
	var query = iq.setQuery('jabber:iq:private');
	query.appendChild(iq.getDoc().createElement('jwchat')).setAttribute('xmlns','jwchat:notes');

	con.send(iq,getAnnotations);
}

var disco;
function getDiscoItems(iq) {
	if (!iq)
		return;
	
	Debug.log(iq.getDoc().xml,2);

	disco = new Array();

	var items = iq.getNode().firstChild.childNodes;

	/* query items */
	for (var i=0; i<items.length; i++) {
		if (items[i].nodeName != 'item' || !items[i].getAttribute('jid') || items[i].getAttribute('node')!=null) // skip those
			continue;
		var aIQ = new JSJaCIQ();
		aIQ.setIQ(items[i].getAttribute('jid'),null,'get','disco_info_'+i);
		aIQ.setQuery("http://jabber.org/protocol/disco#info");
		
		con.send(aIQ,getDiscoInfo);
	}
}

function getDiscoInfo(iq) {
	if (!iq || iq.getType() != 'result')
		return;

	Debug.log(iq.getDoc().xml,2);
	if (iq.getType() == 'result') {
		disco[iq.getFrom()] = iq;
		
		// If the identity does not have a name, set the name to jid
		if(iq.getNode().getElementsByTagName('identity').item(0).getAttribute('name') == null)
			iq.getNode().getElementsByTagName('identity').item(0).setAttribute('name', iq.getFrom());

		// set loghost
		if (iq.getNode().getElementsByTagName('identity').item(0)) {
			if (iq.getNode().getElementsByTagName('identity').item(0).getAttribute('category') == 'store') {
				for (var j=0; j<iq.getNode().getElementsByTagName('feature').length; j++) {
					if (iq.getNode().getElementsByTagName('feature').item(j).getAttribute('var') == 'http://jabber.org/protocol/archive') {
						loghost = iq.getFrom();
						break;
					}
				}
			}
		}
	}
}

var bookmarks;
function getBookmarks(iq) {
	if (!iq || iq.getType() != 'result')
		return;

	Debug.log(iq.getDoc().xml,2);

	bookmarks = new Array();

	if (iq.getNode().getElementsByTagName('storage').item(0)) {
		var jNode = iq.getNode().getElementsByTagName('storage').item(0);
		for (var i=0; i<jNode.childNodes.length; i++) {
			var item = jNode.childNodes.item(i);
			if (item.nodeName == 'conference') {
				var bookmark = new Object();
				bookmark.jid = item.getAttribute('jid');
				bookmark.name = item.getAttribute('name');
				if (item.getAttribute('autojoin') == '1')
					bookmark.autojoin = '1';
				if (item.getElementsByTagName('nick').item(0))
					bookmark.nick = item.getElementsByTagName('nick').item(0).firstChild.nodeValue;
				if (item.getElementsByTagName('pass').item(0))
					bookmark.pass = item.getElementsByTagName('pass').item(0).firstChild.nodeValue;
				bookmarks[bookmarks.length] = bookmark;
				if (bookmark.autojoin == '1') {
					openGroupchat(bookmark.jid, bookmark.nick, bookmark.pass);
				}
			}
		}
	}
}

var annotations;
function getAnnotations(iq) {
	if (!iq || iq.getType() != 'result')
		return;
	
	Debug.log(iq.getDoc().xml,2);
	
	annotations = new Array();

	if (iq.getType() == 'result') {
		if (iq.getNode().getElementsByTagName('jwchat').item(0)) {
			var jNode = iq.getNode().getElementsByTagName('jwchat').item(0);
			for (var i=0; i<jNode.childNodes.length; i++)
				if (jNode.childNodes.item(i).nodeName == 'item' && jNode.childNodes.item(i).firstChild)
					annotations[jNode.childNodes.item(i).getAttribute('jid')] = jNode.childNodes.item(i).firstChild.nodeValue;
		}
	}
}


/************************************************************************
 *                       ******  END HANDLERS  ******* 
 ************************************************************************
 */


/************************************************************************
 *                           ******  INIT  *******
 ************************************************************************
 */
var con, Debug, srcW;
function init() {

	/* initialise debugger */
	if (!Debug || typeof(Debug) == 'undefined' || !Debug.start) {
		if (typeof(Debugger) != 'undefined')
			Debug = new Debugger(DEBUG_LVL,'JWChat ' + cutResource(jid));
		else {
			Debug = new Object();
			Debug.log = function() {};
			Debug.start = function() {};
		}
	}
	if (DEBUG &&  (!USE_DEBUGJID || DEBUGJID == cutResource(jid)))
		Debug.start();

  Debug.log("jid: "+jid+"\npass: "+pass,2);

  /* get some refs to static elements */
  statusLed = frames["jwc_main"].document.getElementById('statusLed');
  statusMsg = frames["jwc_main"].document.getElementById('statusMsg');
  fmd = frames["jwc_main"].iRoster.document;
  
  /* set title */
  document.title = "JWChat - " + nick;

  /* set nick */
  frames["jwc_main"].document.getElementById('myNickname').innerHTML = nick;  

	/* ***
	 * create new connection
	 */
	if (BACKEND_TYPE == 'binding')
		con = new JSJaCHttpBindingConnection(Debug);
	else
		con = new JSJaCHttpPollingConnection(Debug);

	/* register handlers */
	con.registerHandler('iq',handleIQSet);
	con.registerHandler('presence',handlePresence);
	con.registerHandler('message',handleMessage);
	con.registerHandler('message',handleMessageError);
	con.registerHandler('ondisconnect',handleDisconnect);
	con.registerHandler('onconnect',handleConnected);
	con.registerHandler('onerror',handleConError);

	/* connect to remote */
	alert('jid:'+jid +'pass:'+pass);
 
	con.connect(HTTPBASE,JABBERSERVER,jid,'jwchat',pass,timerval,register);
	//con.connect(HTTPBASE,JABBERSERVER,jid.substring(0,jid.indexOf('@')),jid.substring(jid.indexOf('/')+1),pass,timerval,register);
}

/************************************************************************
 *                       ******  LOGOUT  *******
 ************************************************************************
 */

function cleanUp() {
  /* close dependent windows */
	if (roster)
		roster.cleanUp();

  if (subw && !subw.closed)
    subw.close();

	if (typeof(ow) != 'undefined' && ow && !ow.closed)
		ow.close();

	if (searchW && !searchW.closed)
		searchW.close();

	if (ebW && !ebW.closed)
		ebW.close();

  fmd.getElementById('roster').innerHTML = '';

  // clear frames
  frames["jwc_sound"].document.open();
  frames["jwc_sound"].document.write();
  frames["jwc_sound"].document.close();
}

var logoutCalled = false;
function logout() {
	logoutCalled = true;
	cleanUp();

	if (!con.connected())
		return;

	/* save state */
	var iq = new JSJaCIQ();
	iq.setIQ(null,null,'set');
	var query = iq.setQuery('jabber:iq:private');
	var aNode = query.appendChild(iq.getDoc().createElement('jwchat'));
	aNode.setAttribute('xmlns','jwchat:state');

	// save presence
	aNode.appendChild(iq.getDoc().createElement('presence')).appendChild(iq.getDoc().createTextNode(onlstat));
	
	var hiddengroups = '';
	if (typeof(roster) != 'undefined') {
		for (var i in roster.hiddenGroups)
			if (roster.hiddenGroups[i])
				hiddengroups += i+",";
	}

	if (hiddengroups != '')
		aNode.appendChild(iq.getDoc().createElement('hiddenGroups')).appendChild(iq.getDoc().createTextNode(hiddengroups));

	con.syncSend(iq);

	var aPresence = new JSJaCPresence();
	aPresence.setType('unavailable');
	con.syncSend(aPresence);

	con.disconnect();
}

/************************************************************************
 *                     ******  INITIALISE VARS  *******
 ************************************************************************
 */

/* check for unsupported browsers */
if (is.b == 'op' || 
    is.b == 'Konqueror' || 
    navigator.userAgent.indexOf('Safari') != -1 ||
    (is.b == 'ns' && is.v < '5') ||
    (is.ie && is.mac) ||
    is.ie4
    ) 
  {
    open("unsupported.html","unsupported","width=380,height=180");
  }


/* quick hack - need this info before onload */
/* get args */
getArgs();

var JABBERSERVER;
var BACKEND_TYPE;
var HTTPBASE;

// Here is the config info.
jid = getCookie("jid");
alert("cjwchat:jid:from cookie:" + jid);

if(!jid)
{
	jid = getNewUser();	
	setCookie("jid", jid, getExpDate(1000, 0, 0));
	register = true;
}
alert("cjwchat:jid:" + jid);


// Get a new user from server 
// Wait until get success.
// Save to cookie
function getNewUser()
{
	return getGuid();
}

pass = "dragon";
//jid = "demo@yuying/jwchat";

BACKEND_TYPE = "binding";
HTTPBASE = "JHB/";

register = false;

if (!isValidJID(jid))
  window.close();

nick = jid.substring(0,jid.indexOf('@'));

function updateStyleIE() {
  if (roster)
    roster.updateStyleIE();
}

function comboAction()
{
	init();
	
	hideWindow();
	
	beginChat();
	
}

function beginChat()
{
	var chatto = "demo";
	alert("chat with jid JABBERSERVER:"+JABBERSERVER);
	//alert(chatto + "@" + JABBERSERVER);
	roster.openChat(chatto + "@" + JABBERSERVER);
}

function hideWindow()
{
	window.menubar = false;	
	//'height=100,width=400,top=0,left=0,toolbar=no,menubar=no,scrollbars=no, resizable=no,location=no, status=no') 
	window.resizeTo(0, 0);
}


onload = comboAction;
onunload = logout;
onresize = updateStyleIE;

//-->
    </script>
    <script src="roster.js"></script>
  </head>
  <frameset rows="0,0" border="0">
    <frame src="croster.html" width="0" height="0" name="jwc_main" marginwidth="0" marginheight="0" scrolling="no">
    <frame src="empty.html" name="jwc_sound" marginwidth="0" marginheight="0" onLoad="soundLoaded();">
  </frameset><noframes></noframes>
  <body>
  </body>
</html>
